import { Injectable, Logger } from '@nestjs/common';
import OpenAI from 'openai';
import { ConfigService } from '@nestjs/config';
import { InfoService } from '../info/info.service';
import { QueryInfoDto } from '../info/dto/info.dto';
import { RecordsService } from '../records/records.service';
import { SessionService } from '../session/session.service';
import { ResultData } from '../../../common/utils/result';
import { SpectrumService } from '../spectrum/spectrum.service';
import RPCClient = require('@alicloud/pop-core');
import axios from 'axios';

@Injectable()
export class AiService {
  private readonly openai: OpenAI;
  private readonly client: RPCClient;
  private readonly logger = new Logger(AiService.name);

  private readonly apiKey = 'lm-7F7at2+J+7Szneo7w0eTBA==';
  private readonly serviceName = 'aca-chat-send-sse'; // 角色扮演接口（非流式）
  private readonly url = 'https://nlp.aliyuncs.com/v2/api/chat/send';

  constructor(
    private configService: ConfigService,
    private readonly infoService: InfoService,
    private readonly recordsService: RecordsService,
    private readonly sessionService: SessionService,
    private readonly spectrumService: SpectrumService,
  ) {
    // 初始化OpenAI客户端，对接阿里云百炼
    this.openai = new OpenAI({
      apiKey: this.configService.get<string>('aliyun.dashScope'),
      baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
    });

    // 初始化阿里云RPC客户端
    this.client = new RPCClient({
      accessKeyId: this.configService.get<string>('aliyun.accessKeyId'),
      accessKeySecret: this.configService.get<string>('aliyun.accessKeySecret'),
      endpoint: 'http://nls-meta.cn-shanghai.aliyuncs.com',
      apiVersion: '2019-02-28',
    });
  }

  /**
   * 调用通义千问模型生成回答
   * @param messages 对话消息列表
   * @param model 模型名称，默认使用qwen-plus
   * @returns 生成的回答内容
   */
  async generateCompletion(messages: Array<{ role: 'system' | 'user' | 'assistant'; content: string }>, model: string = 'qwen-plus') {
    try {
      this.logger.log(`调用AI模型: ${model}, 消息: ${JSON.stringify(messages)}`);

      const completion = await this.openai.chat.completions.create({
        model,
        messages,
      });

      this.logger.log('AI响应成功');
      return completion.choices[0].message.content;
    } catch (error) {
      this.logger.error('AI调用失败', error.stack);
      throw new Error(`AI服务调用失败: ${error.message}`);
    }
  }

  /**
   * 简单的问答接口
   * @param question 用户问题
   * @param systemPrompt 系统提示词
   * @returns 回答内容
   */
  async askQuestion(question: string, systemPrompt: string = 'You are a helpful assistant.') {
    return this.generateCompletion([
      { role: 'system', content: systemPrompt },
      { role: 'user', content: question },
    ]);
  }

  /**
   * 获取上周一的开始时间字符串
   * @returns 上周一的日期字符串 (YYYY-MM-DD 00:00:00)
   */
  getLastMonday(): string {
    const today = new Date();
    const dayOfWeek = today.getDay(); // 0为周日，1为周一，以此类推
    const daysSinceMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1; // 计算距离本周一的天数
    const lastMonday = new Date(today);
    lastMonday.setDate(today.getDate() - daysSinceMonday - 7); // 回到上周一
    lastMonday.setHours(0, 0, 0, 0); // 设置为当天的开始时间
    return lastMonday.toISOString().slice(0, 19).replace('T', ' ');
  }

  /**
   * 根据指定时间获取上周的开始和结束时间
   * @param {Date|string|number} date - 指定的时间，可以是Date对象、日期字符串或时间戳
   * @returns {Object} 包含start和end属性的对象，分别表示上周的开始和结束时间
   */
  // getCorrectLastWeekByDate(date) {
  //   // 确保输入是Date对象，如果是字符串则尝试解析
  //   const inputDate = typeof date === 'string' ? new Date(date) : date;
  //
  //   if (!(inputDate instanceof Date) || isNaN(inputDate.getTime())) {
  //     throw new Error('请提供有效的日期');
  //   }
  //
  //   // 创建一个新日期，避免修改原始日期
  //   const workingDate = new Date(inputDate);
  //
  //   // 关键修复：使用UTC方法进行计算，避免时区影响
  //   const day = workingDate.getDay() || 7; // 转换为1-7，1是周一，7是周日
  //
  //   // 计算上周一的日期
  //   const lastMonday = new Date(workingDate);
  //   lastMonday.setDate(workingDate.getDate() - day - 6);
  //   lastMonday.setUTCHours(0, 0, 0, 0);
  //
  //   // 计算上周日的日期
  //   const lastSunday = new Date(lastMonday);
  //   lastSunday.setDate(lastMonday.getDate() + 6);
  //   lastSunday.setUTCHours(23, 59, 59, 999);
  //
  //   return {
  //     start: lastMonday,
  //     end: lastSunday,
  //     // 增加格式化输出，方便查看
  //     startStr: `${lastMonday.getUTCFullYear()}-${String(lastMonday.getUTCMonth() + 1).padStart(2, '0')}-${String(lastMonday.getDate()).padStart(2, '0')} 00:00:00`,
  //     endStr: `${lastSunday.getUTCFullYear()}-${String(lastSunday.getUTCMonth() + 1).padStart(2, '0')}-${String(lastSunday.getDate()).padStart(2, '0')} 23:59:59`,
  //   };
  // }

  /**
   * 根据指定时间获取上周的开始和结束时间
   * @param {Date|string|number} date - 指定的时间，可以是Date对象、日期字符串或时间戳
   * @returns {Object} 包含start和end属性的对象，分别表示上周的开始和结束时间
   */
  getCorrectLastWeekByDate(date) {
    // 确保输入是Date对象
    const inputDate = typeof date === 'string' ? new Date(date) : date;
    if (!(inputDate instanceof Date) || isNaN(inputDate.getTime())) {
      throw new Error('请提供有效的日期');
    }

    // 基于本地时区计算（去掉UTC方法）
    const workingDate = new Date(inputDate);
    let day = workingDate.getDay(); // 本地时区：0=周日，1=周一，...，6=周六

    // 转换为：1=周一，7=周日（与业务逻辑一致）
    day = day === 0 ? 7 : day;

    // 计算上周一（本地时区）
    const lastMonday = new Date(workingDate);
    // 核心公式：当前日期 - 本周已过的天数（day） - 6天（因为要到上周一）
    lastMonday.setDate(workingDate.getDate() - day - 6);
    lastMonday.setHours(0, 0, 0, 0);

    // 计算上周日（本地时区）
    const lastSunday = new Date(lastMonday);
    lastSunday.setDate(lastMonday.getDate() + 6);
    lastSunday.setHours(23, 59, 59, 999);

    // 格式化输出（使用本地时区方法）
    const format = (date) => {
      const year = date.getFullYear();
      const month = String(date.getMonth() + 1).padStart(2, '0');
      const day = String(date.getDate()).padStart(2, '0');
      const hours = String(date.getHours()).padStart(2, '0');
      const minutes = String(date.getMinutes()).padStart(2, '0');
      const seconds = String(date.getSeconds()).padStart(2, '0');
      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    };

    return {
      start: lastMonday,
      end: lastSunday,
      startStr: format(lastMonday),
      endStr: format(lastSunday),
    };
  }

  async generateTestAIReport() {
    try {
      this.logger.error('开始生成AI报告'); // 使用Nest的日志服务
      const testDate = new Date();
      const lastWeek = this.getCorrectLastWeekByDate(testDate);

      console.log('啦啦啦');
      // const infoList = await this.infoService.findAllList();

      // console.log('啦啦啦');
      // if (!infoList || infoList.length === 0) {
      //   this.logger.log('没有会员数据');
      //   return;
      // }
      // // 存储处理结果
      // const results = [];
      //
      // // 使用 for...of 替代 forEach 来正确处理异步操作
      // for (const info of infoList)
      //   try {
      //     const messages = [];
      //     const recordsList = await this.recordsService.get(info.userId, lastWeek.startStr, lastWeek.endStr);
      //
      //     // 检查是否有足够的记录数据
      //     const totalContentLength = recordsList.reduce((acc, record) => acc + (record.content?.length || 0) + (record.aiReply?.length || 0), 0);
      //
      //     // 使用 for...of 替代内层 forEach
      //     for (const record of recordsList) {
      //       messages.push({ role: 'user', content: record.content });
      //       messages.push({ role: 'assistant', content: record.aiReply });
      //     }
      //
      //     // 构建系统提示词
      //     const systemPrompt =
      //       '你是一名"周度心理对话评估"助手。你将收到【一周聊天记录】。请在内部先完成要点提取与打分，再只输出 JSON（不得包含多余文字或代码块标记）。\n' +
      //       '\n' +
      //       '【评估维度｜0–100 分，分数越高表示该维度"表现越明显/越强烈"（不代表好坏）】\n' +
      //       '1) 情绪流露 emotion_flow：负面或强烈情绪出现的频率与强度（如"崩溃/烦死了/伤心/绝望/生气/焦虑"等；感叹号、夸张副词、哭泣表情等增强强度）。\n' +
      //       '   低=几乎不表露；中=偶尔表露；高=频繁且强烈。\n' +
      //       '2) 自我表达 self_expression：表达是否清晰、具体、有结构（包含情境-原因-感受-需求/打算；使用"因为/所以/导致/我认为"等连接与反思）。\n' +
      //       '   低=含糊、跳跃；中=能表达但不深入；高=具体完整、能反思。\n' +
      //       '3) 行为归因 behavior_attribution：归因倾向的显著度（持续内归因如"我没用/都是我不好"，或持续外归因如"老师/制度/运气不好"）。\n' +
      //       '   低=少见或摇摆；中=有一定倾向；高=明显且稳定的单一倾向。\n' +
      //       '4) 困境应对 difficulty_coping：面对压力/任务时的无助、回避、停摆等表现（如"不知道怎么办/想躺平/拖延/放弃/崩不住了"）。\n' +
      //       '   低=能提出办法；中=有困难但尝试；高=明显无助或回避。\n' +
      //       '5) 互动主动 interaction_initiative：主动联系、求助、沟通与维系关系的意愿与行为（"找同学/老师聊/咨询/求助/约见/参加活动"）。\n' +
      //       '   低=回避社交；中=偶有尝试；高=主动多次。\n' +
      //       '\n' +
      //       '【打分办法（内部执行，最终只给数字）】\n' +
      //       '- 先在内部列出证据点→按低/中/高映射为大致区间：低(10–35)、中(40–65)、高(70–90)；极端强烈可到(95)。\n' +
      //       '- 结合频率与强度取整到 0–100 的**整数**。\n' +
      //       '\n' +
      //       '【标签生成】\n' +
      //       '- 从下列词表中选 2–5 个，用"、"分隔：情绪低落、情绪波动、焦虑紧张、兴趣减退、社交困难、回避求助、自我贬低、过度担责、外部归因、学习压力、睡眠困扰、注意力分散、无助无望、冲突矛盾、积极求助、目标不清。\n' +
      //       '- 若无足够证据，选"信息不足"。\n' +
      //       '\n' +
      //       '【文字报告】\n' +
      //       '- 以客观第三人称撰写 180–280 字中文总结，逐维度点到为止，可引用少量原话（不加引号也可），避免诊断性用语。\n' +
      //       '- 如聊天内容少于 50 字或与心理无关，五维统一给"50"，并说明"数据不足，需补充样本"。\n' +
      //       '\n' +
      //       '【严格输出】\n' +
      //       '- 只输出以下 JSON，键名与顺序固定，值类型均为字符串整数（0–100），不得出现多余字段、注释或换行外文本。\n' +
      //       '\n' +
      //       '{\n' +
      //       '  "emotion_flow": "0-100",\n' +
      //       '  "self_expression": "0-100",\n' +
      //       '  "behavior_attribution": "0-100",\n' +
      //       '  "difficulty_coping": "0-100",\n' +
      //       '  "interaction_initiative": "0-100",\n' +
      //       '  "report_tags": "标签1、标签2",\n' +
      //       '  "report_content": "180-280字客观总结"\n' +
      //       '}\n' +
      //       '\n' +
      //       '【一周聊天记录】=<<<在此粘贴原始文本>>>\n';
      //
      //     // 如果数据不足，添加特殊标记
      //     if (totalContentLength < 50) {
      //       messages.push({
      //         role: 'system',
      //         content: systemPrompt + '\n\n【注意】聊天内容不足，数据不足，需补充样本',
      //       });
      //     } else {
      //       messages.push({
      //         role: 'system',
      //         content: systemPrompt,
      //       });
      //     }
      //
      //     // 调用AI生成报告
      //     const aiResponse = await this.generateCompletion(messages);
      //
      //     const json = JSON.parse(aiResponse);
      //     this.logger.log(`AI报告生成完成，结果为：${JSON.stringify(json, null, 2)}`);
      //     // 保存生成的报告
      //     this.spectrumService.create({
      //       childId: info.userId,
      //       reportContent: json.report_content,
      //       reportTags: json.report_tags,
      //       emotionFlow: json.emotion_flow,
      //       selfExpression: json.self_expression,
      //       behaviorAttribution: json.behavior_attribution,
      //       difficultyCoping: json.difficulty_coping,
      //       interactionInitiative: json.interaction_initiative,
      //       startTime: lastWeek.startStr,
      //       endTime: lastWeek.endStr,
      //     });
      //
      //     // 处理AI响应结果
      //     const result = {
      //       userId: info.userId,
      //       report: aiResponse,
      //       generatedAt: new Date(),
      //     };
      //
      //     results.push(result);
      //     this.logger.log(`成功为用户 ${info.userId} 生成AI报告`);
      //   } catch (error) {
      //     this.logger.error(`为用户 ${info.userId} 生成AI报告时出错:`, error.stack);
      //     // 继续处理下一个用户，不中断整个流程
      //   }

      // return ResultData.ok(results);
    } catch (error) {
      this.logger.error('生成AI报告过程中发生错误:', error.stack);
      throw new Error(`生成AI报告失败: ${error.message}`);
    }
  }

  async generateAIReport() {
    try {
      const testDate = new Date();
      const lastWeek = this.getCorrectLastWeekByDate(testDate);
      const infoList = await this.infoService.findAllList();
      if (!infoList || infoList.length === 0) {
        this.logger.log('没有会员数据');
        return;
      }
      // 存储处理结果
      const results = [];

      // 使用 for...of 替代 forEach 来正确处理异步操作
      for (const info of infoList)
        try {
          const messages = [];
          const recordsList = await this.recordsService.get(info.userId, lastWeek.startStr, lastWeek.endStr);

          // 检查是否有足够的记录数据
          const totalContentLength = recordsList.reduce((acc, record) => acc + (record.content?.length || 0) + (record.aiReply?.length || 0), 0);

          // 使用 for...of 替代内层 forEach
          for (const record of recordsList) {
            messages.push({ role: 'user', content: record.content });
            messages.push({ role: 'assistant', content: record.aiReply });
          }

          // 构建系统提示词
          const systemPrompt = `你是一名 “周度心理对话评估” 助手，核心评估原则：未提及的维度内容仅客观说明 “未提及”，不做 “不爱 / 回避” 等主观推断；总结需含量化信息；语言无专业心理术语且委婉。收到【一周聊天记录】后，先内部提取有证据的要点与打分，再只输出 JSON（无多余文字或代码块标记）。
                【评估维度｜0–100 分，分数越高表示该维度 “表现越明显 / 越强烈”（不代表好坏）】
                情绪流露 emotion_flow：负面或强烈情绪出现的频率与强度（如 “烦 / 气死了” 等表述；感叹号、消极语气词等增强强度）。低 = 几乎不表露；中 = 偶尔表露；高 = 频繁且强烈。
                自我表达 self_expression：表达是否清晰、具体（是否含情境 - 原因；是否用 “因为 / 所以” 梳理逻辑）。低 = 含糊、跳跃；中 = 能表达但不深入；高 = 具体完整、能反思。
                行为归因 behavior_attribution：归因倾向的显著度（持续内归因如 “我没做好”，或持续外归因如 “老师没讲清”）。低 = 少见或摇摆；中 = 有一定倾向；高 = 习惯单一归因。
                困境应对 difficulty_coping：面对压力 / 任务时无助、回避的表现（如 “想放弃 / 装肚子疼 / 到时候再说”）。低 = 能主动提办法；中 = 有困难但愿尝试；高 = 易出现回避想法。
                互动主动 interaction_initiative：主动社交、求助的意愿与行为（“找同学问问题 / 约见面 / 参加活动”）。低 = 未提及主动互动；中 = 偶有主动互动表述；高 = 多次提及主动互动。
                【打分办法（内部执行，最终只给数字）】
                仅基于有明确提及的内容列证据点（未提及维度不强行关联），按低 (10–35)、中 (40–65)、高 (70–90) 映射区间；极端强烈可到 (95)。
                结合情绪 / 行为的 “出现次数” 与 “强度” 取整为 0–100 的整数。
                【标签生成】
                仅从有证据支撑的维度选 2–5 个词，用 “、” 分隔：情绪低落、情绪波动、兴趣减退、社交困难、回避求助、自我贬低、过度担责、外部归因、学习压力、睡眠困扰、注意力分散、无助无望、冲突矛盾、积极求助、目标不清。
                未提及相关内容时不选对应标签；整体证据不足选 “信息不足”。
                【文字报告】
                以客观第三人称撰写 180–280 字总结，每个提及的维度需标注量化信息（如 “3 次流露负面情绪”“4 次出现回避想法”），未提及维度表述为 “未提及 XX 相关事件，无法判断具体情况”。
                禁用 “抑郁”“焦虑”“归因偏差” 等专业心理术语，需使用生活化委婉表述：描述归因时可用 “更习惯从外部找原因” 或 “习惯从自身找问题原因”；描述面对困境的表现时可用 “易出现回避想法”；描述社交相关情况时，若未提及主动行为则说明 “未提及主动社交相关事件”；描述对事情的担忧时可用 “面对事情时担忧较多”。
                若聊天内容少于 50 字或与心理无关，五维统一给 “50”，并说明 “数据不足，需补充样本”。
                【严格输出】
                只输出以下 JSON，键名与顺序固定，值类型均为字符串整数（0–100），无多余字段、注释或换行外文本。
                {"emotion_flow": "0-100","self_expression": "0-100","behavior_attribution": "0-100","difficulty_coping": "0-100","interaction_initiative": "0-100","report_tags": "标签 1、标签 2","report_content": "180-280 字客观总结（含量化信息 + 委婉表述，未提及内容不妄断）"}
                【一周聊天记录】=<<<在此粘贴原始文本>>>`;

          // 如果数据不足，添加特殊标记
          if (totalContentLength < 50) {
            messages.push({
              role: 'system',
              content: systemPrompt + '\n\n【注意】聊天内容不足，数据不足，需补充样本',
            });
          } else {
            messages.push({
              role: 'system',
              content: systemPrompt,
            });
          }

          // 调用AI生成报告
          const aiResponse = await this.generateCompletion(messages);

          const json = JSON.parse(aiResponse);
          this.logger.log(`AI报告生成完成，结果为：${JSON.stringify(json, null, 2)}`);
          // 保存生成的报告
          this.spectrumService.create({
            childId: info.userId,
            reportContent: json.report_content,
            reportTags: json.report_tags,
            emotionFlow: json.emotion_flow,
            selfExpression: json.self_expression,
            behaviorAttribution: json.behavior_attribution,
            difficultyCoping: json.difficulty_coping,
            interactionInitiative: json.interaction_initiative,
            startTime: lastWeek.startStr,
            endTime: lastWeek.endStr,
          });

          // 处理AI响应结果
          const result = {
            userId: info.userId,
            report: aiResponse,
            generatedAt: new Date(),
          };

          results.push(result);
          this.logger.log(`成功为用户 ${info.userId} 生成AI报告`);
        } catch (error) {
          this.logger.error(`为用户 ${info.userId} 生成AI报告时出错:`, error.stack);
          // 继续处理下一个用户，不中断整个流程
        }

      return ResultData.ok(results);
    } catch (error) {
      this.logger.error('生成AI报告过程中发生错误:', error.stack);
      throw new Error(`生成AI报告失败: ${error.message}`);
    }
  }

  /**
   * 创建阿里云Token
   * @returns 包含Token信息的对象
   */
  async createToken(): Promise<any> {
    try {
      const result: any = await this.client.request('CreateToken', {});
      // 如果有 Token 信息则返回，否则返回完整响应供调试
      return ResultData.ok(result);
    } catch (error) {
      this.logger.error('Failed to create Aliyun token:', error.stack);
      throw new Error(`Failed to create Aliyun token: ${error.message}`);
    }
  }

  async sendChatMessage() {
    const headers = {
      'Content-Type': 'application/json',
      'X-AcA-DataInspection': 'enable',
      'x-fag-servicename': this.serviceName,
      'x-fag-appcode': 'aca',
      'X-AcA-SSE': 'enable',
      Authorization: `Bearer ${this.apiKey}`,
    };

    const payload = {
      input: {
        messages: [{ role: 'user', content: '你好' }],
        aca: {
          botProfile: {
            characterId: 'fb3b03077eb34544a85dcb13bf94d4e4',
          },
          userProfile: {
            userId: '123456', // 可自定义userId
          },
          scenario: {
            description: '',
          },
          context: {
            useChatHistory: false, // false表示使用传入的对话历史
          },
        },
      },
    };

    try {
      const response = await axios.post(this.url, payload, { headers });
      console.log('Status Code:', response.status);
      console.log('Response Data:', response.data);
      return response.data;
    } catch (error) {
      console.error('Request failed:', error.response?.status, error.response?.data);
      throw error;
    }
  }
}
